package com.beverages.individual.config.interceptor;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.beverages.individual.common.Constants;
import com.beverages.individual.config.AuthAccess;
import com.beverages.individual.entity.Individual;
import com.beverages.individual.exception.ServiceException;
import com.beverages.individual.service.IIndividualService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(JwtInterceptor.class);

    @Autowired
    private IIndividualService individualService;

    private static final String FEIGN_HEADER = "X-Feign-Request";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 如果请求头中有 X-Feign-Request，则放行（表示这是 Feign 请求）
        String feignHeader = request.getHeader(FEIGN_HEADER);
        logger.info("Feign 请求头 X-Feign-Request: {}", feignHeader);
        if (StrUtil.isNotBlank(feignHeader)) {
            return true; // Feign 请求直接放行
        }

        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod h = (HandlerMethod) handler;
        // 检查方法上是否有 AuthAccess 注解，有则直接放行
        AuthAccess authAccess = h.getMethodAnnotation(AuthAccess.class);
        if (authAccess != null) {
            return true; // 放行不受保护的资源
        }

        // 排除特定的登录请求，避免被拦截
        String requestURI = request.getRequestURI();
        if (requestURI.equals("/merchant/individual/login")) {
            return true; // 如果是登录请求，直接放行
        }

        // 记录被拦截的请求信息
        logger.info("拦截请求：{} {}，请求来源IP：{}", request.getMethod(), requestURI, request.getRemoteAddr());

        String token = request.getHeader("token");

        // 执行认证
        if (StrUtil.isBlank(token)) {
            logger.warn("请求 {} 被拦截：无 token", requestURI); // 记录无 token 的请求
            throw new ServiceException(Constants.CODE_401, "无token，请重新登录");
        }

        // 获取 token 中的 individual id
        String individualId;
        try {
            individualId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            logger.warn("请求 {} 被拦截：token 验证失败，解析错误", requestURI); // 记录 token 解析失败的请求
            throw new ServiceException(Constants.CODE_401, "token验证失败，请重新登录");
        }

        // 根据 token 中的 individualId 查询数据库
        Individual individual = individualService.getById(individualId);
        if (individual == null) {
            logger.warn("请求 {} 被拦截：用户不存在，individualId: {}", requestURI, individualId); // 记录用户不存在的请求
            throw new ServiceException(Constants.CODE_401, "用户不存在，请重新登录");
        }

        // 用户密码加签验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(individual.getPassword())).build();
        try {
            jwtVerifier.verify(token); // 验证 token
        } catch (JWTVerificationException e) {
            logger.warn("请求 {} 被拦截：token 验证失败，签名错误", requestURI); // 记录签名错误的请求
            throw new ServiceException(Constants.CODE_401, "token验证失败，请重新登录");
        }

        // 记录请求通过
        logger.info("请求 {} 通过认证，继续处理", requestURI);

        return true;
    }
}